package sparrowGui.utils
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.InteractiveObject;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.SimpleButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.DropShadowFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.utils.ByteArray;
	import flash.utils.describeType;
	
	import sparrowGui.item.Item;

	/**
	 * 控制容器相关的工具函数
	 * @author Pelephone
	 */	
	public class PubFun
	{
		/**
		 * 返回指定类型的孩子
		 * @param node		被寻找的父节点
		 * @param tClass	子类孩子的过滤, 如果为 null, 则返回第一个孩子
		 */
		static public function findChild(node:DisplayObjectContainer, tClass:Class=null):DisplayObject{
			if(tClass == null) tClass = DisplayObject;
			for(var i:int=0; i<node.numChildren; i++){
				var disp:DisplayObject = node.getChildAt(i);
				if(disp is tClass) return disp;
			}
			return null;
		}
		
		/**
		 *  从数组里找属性为propName,值等于values参数其中一项的项数组
		 * 如果arr=[{name:1},{name:2},{name:3}]; arr2 = findArr(arr,"name",[2,3]) arr2为[{name:2},{name:3}]
		 * arr2 = findArr(arr,"name",2) 结果为{name:2}
		 */
		static public function findArr(arr:Array,propName:String,values:Object):*
		{
			if((values is Number) || (values is String) || !resArr.length){
				for each(var o:Object in arr){
					if(o[propName]==values) return o;
				}
				return null;
			}
			var resArr:Array = [];
			for each(o in arr){
				if(values.indexOf(o[propName])>=0) resArr.push(o);
			}
			return resArr;
		}
		
		// 安全移除
		public static function SafeRemoveChild(disp:DisplayObject) : void
		{
			if (disp && disp.parent)	disp.parent.removeChild(disp);
		}
		
		/**
		 * 清除容器里面的所有显示对象
		 * @param s
		 */		
		static public function clearDisp(s:DisplayObjectContainer):void
		{
			if(s) while(s.numChildren) s.removeChildAt(0);
		}
		
		/** 判断是否子窗口, 返回 0=相等, >0=是父子关系, -1=非父子关系*/
		static public function isChild(parent:DisplayObjectContainer, child:DisplayObject):int{
			if(!child || !parent) return -1;
			var deep:int = 0;
			while(child != parent){
				child = child.parent;
				if(!child) return -1;
				deep ++;
			}
			return deep;
		}
		
		/**
		 * 对齐2个控件的位置
		 * @param ref		参考位置
		 * @param disp		改变的位置
		 * @param align		对齐方式 "T" 顶对齐,"B" 底对齐,"L" 左对齐,"R" 右对齐,"C" 水平居中对齐,"M"垂直居中
		 * 					"S" 拉伸，使disp的长宽和ref相同
		 */
		static public function alignRect(ref:DisplayObject, disp:DisplayObject,align:String="T"):void
		{
			//左对齐
			if(align.indexOf("T")>=0){
				if(disp.parent == ref) disp.y = 0;
				else disp.y = ref.y;
			}
			//底对齐
			if(align.indexOf("B")>=0){
				if(disp.parent == ref) disp.y = ref.height - disp.height;
				else disp.y = ref.y + ref.height - disp.height;
			}
			//左对齐
			if(align.indexOf("L")>=0){
				if(disp.parent == ref) disp.x = 0;
				else disp.x = ref.x;
			}
			//右对齐
			if(align.indexOf("R")>=0){
				if(disp.parent == ref) disp.x = ref.width - disp.width;
				else disp.x = ref.x + ref.width - disp.width;
			}
			//水平居中
			if(align.indexOf("C")>=0){
				if(disp.parent == ref) disp.x = ref.width/2 - disp.width/2;
				else disp.x = ref.x + ref.width/2 - disp.width/2;
			}
			//垂直居中
			if(align.indexOf("M")>=0){
				if(disp.parent == ref) disp.y = ref.height/2 - disp.height/2;
				else disp.y = ref.y + ref.height/2 - disp.height/2;
			}
			//拉伸，使disp的宽和ref相同
			if(align.indexOf("W")>=0){
				disp.width = ref.width;
			}
			//拉伸，使disp的长和ref相同
			if(align.indexOf("H")>=0){
				disp.height = ref.height;
			}
		}
		
		/**
		 * 设置所有孩子的属性值
		 * @param parent		父窗口
		 * @param propName		属性名
		 * @param propValue		属性值
		 * @param childType		孩子类型, 用来过滤, 默认为 null 表示 不过滤
		 * @param exclude		要排除的孩子列表
		 */
		static public function setChildrenProperty(parent:DisplayObjectContainer, propName:String, propValue:Object, childType:Class=null, ...exclude):void{
			
			// 孩子类型
			if(childType == null) childType = DisplayObject;
			
			// 遍历每个孩子
			var num:int = parent.numChildren;
			for(var index:int=0; index<num; index++){
				
				// 类型过滤
				var child:DisplayObject = parent.getChildAt(index);
				if(! (child is childType) ) continue;
				
				// 排除列表
				if(exclude.indexOf(child) >= 0) continue;
				
				// 设置孩子的属性
				child[propName] = propValue;
			}
		}
		
		/**
		 * 将新显示容器附上占位的属性后删除占位
		 * @param tarDisp		新显示容器
		 * @param zwDisp		点位容器
		 * @param properties	属性字符，默认是x,y,宽,高
		 */		
		static public function addChildToZW(tarDisp:DisplayObject,zwDisp:DisplayObject,copyProps:String="x,y,width,height"):void
		{
			copyProperties(tarDisp,zwDisp,copyProps);
			if(tarDisp.scaleX==0 || tarDisp.scaleY==0){
				throw new Error("复制属性错误, 该窗口将无法被显示");	// 可能尺寸为0
			}
			
			zwDisp.parent.addChild(tarDisp);
			zwDisp.parent.swapChildren(zwDisp, tarDisp);
			SafeRemoveChild(zwDisp);
		}
		
		/**
		 * 将场景里面的五态显示对象换成有事件的item
		 * @param tarDisp
		 * @param itemCla	此Class必须继承item
		 * @return
		 */		
		static public function changeSP2Item(tarDisp:DisplayObject,itemCla:Class=null,txt:String=null,vars:Object=null):Item
		{
			if(!tarDisp || tarDisp is SimpleButton) return null;
			itemCla = (itemCla==null)?Item:itemCla; 
			var parent:DisplayObjectContainer = tarDisp.parent;
			var id:int = tarDisp.parent.getChildIndex(tarDisp);
			var btn:Item = (new itemCla(null,tarDisp,vars)) as Item;
			btn.x = tarDisp.x;
			btn.y = tarDisp.y;
			tarDisp.x = 0;
			tarDisp.y = 0;
			btn.name = tarDisp.name;
			parent.addChildAt(btn,id);
			if(txt) setSimpleButtonText(tarDisp,txt);
			return btn;
		}
		
		/**
		 * 返回最大的孩子
		 */
		static public function maxChild(backmc:DisplayObjectContainer):InteractiveObject{
			var maxChild:InteractiveObject = findChild(backmc, InteractiveObject) as InteractiveObject;
			if(maxChild.width == backmc.width && maxChild.height==backmc.height) return maxChild;
			return backmc;
		}
		
		/**
		 * 得到本地鼠标坐标
		 */
		static public function getLocalMousePoint(disp:DisplayObject):Point{
			trace("getLocalMousePoint for test");
			var x:int = 0;
			var y:int = 0;
			if(disp && disp.stage){
				x = disp.stage.mouseX;
				y = disp.stage.mouseY;
			}
			return disp.globalToLocal( new Point(x, y) );
		}
		
		/**
		 * 通过propNameList复制对象属性
		 */
		static public function copyProperties(dst:Object, src:Object, propNameList:String):void{
			if(!dst || !src || !propNameList) return;
			var exp:RegExp = /(\w+)/g;
			var arr:Array = propNameList.match( exp );
			for each(var prop:String in arr){
				dst[prop] = src[prop];
			}
		}
		
		/**
		 * 复制srcObj对象的属性给refObj，如果原对象与新对象的属性名相同，并且类型相同则复制属性值。
		 * (属性必须是public型)
		 * @param obj
		 * @param defaultClass
		 * @param ignoreProps
		 * @param isStrict		是否严格匹配，即srcObj上的属性必须不为0才赋值给refObj
		 * @return 
		 */
		static public function parseObjToNew(srcObj:Object, refObj:Object, ignoreProps:Array=null, isStrict:Boolean=false):Object
		{
			var desc:XMLList = describeType( srcObj )["variable"];
			// 设置 obj 的每个属性 prop
			for each(var prop:XML in desc)
			{
				var propName:String = prop.@name;			// 变量名
				var propType:String = prop.@type;			// 变量类型
				
				// 忽略了
				if(ignoreProps && ignoreProps.indexOf(propName)>=0) continue;
				//严格匹配
				if(isStrict && !srcObj[propName]) continue;
				
				// 如果类型一样则复制
				if(refObj.hasOwnProperty(propName)){
					refObj[propName] = srcObj[propName];
				}
			}
			return refObj;
		}
		
		/**
		 * 复制一个对象
		 * @param obj1 要被复制的对象
		 * @return Object 返回复制出的数对象
		 */		
		public static function copyObj(obj1:Object):Object
		{
			var byteArray:ByteArray=new ByteArray();
			byteArray.writeObject(obj1);
			
			byteArray.position=0;
			var obj2:Object=byteArray.readObject();
			return obj2;
		}
		
		/**
		 * 清理对象里的所有引用对象,一般是要删除某对象时用此方法
		 * @param obj
		 * @return 
		 */		
		public static function killObject(obj:Object):Object
		{
			for(var strName:String in obj){
				if((obj[strName] is Number) || (obj[strName] is String)) continue;
				if(obj[strName] is DisplayObject){
					SafeRemoveChild(obj[strName] as DisplayObject);
				}
				obj[strName]=null;
			}
			return obj;
		}
		
		/**
		 * 设置按钮中的文字
		 * @param btn		目标按钮
		 * @param text		新的文字, 当为 null 时, 不设置新文本(仅返回原先的文本)
		 * @param isHtml	是否是html文本
		 * @return			返回新的文本内容
		 */
		static public function setSimpleButtonText(btn:DisplayObject, text:String=null, isHtml:Boolean = false):String{
			
			//
			var prevText:String = "";
			text = text || "";
			
			//
			var list:Array = [ btn["upState"], btn["downState"], btn["overState"], btn["hitTestState"],btn];
			if(btn.hasOwnProperty("selectState")) list.push(btn["selectState"]);
			for each(var disp:DisplayObject in list)
			{
				var tf:TextField = disp as TextField;
				if(tf == null){
					var cont:DisplayObjectContainer = disp as DisplayObjectContainer;
					if(cont) tf = findChild(cont, TextField) as TextField;
				}
				if(tf){
					if(isHtml){
						tf.htmlText = text;
					}else{
						tf.text = text;
					}
					prevText = tf.text;
				} 
			}
			
			//
			return text || prevText;
		}
		
		/**
		 * 复制出一个新的显示对象
		 * @param src
		 * @return 
		 */
		static public function copy_instance(src:DisplayObject):DisplayObject{
			if(src == null) return null;
			var disp:DisplayObject = (new (src as Object).constructor ) as DisplayObject;
			if(disp is MovieClip){
				(disp as MovieClip).gotoAndStop( (src as MovieClip).currentFrame );
			}
			return disp;
		}
		
		/**
		 * 删除指定类型的孩子
		 */
		static public function removeChildrenByType(node:DisplayObjectContainer, tClass:Class=null):void{
			
			if(tClass == null) tClass = DisplayObject;
			var i:int = 0;
			while(i < node.numChildren)
			{
				var disp:DisplayObject = node.getChildAt(i);
				if(disp is tClass) node.removeChildAt(i);
				else i++;
			}
		}
		
		/**
		 * 返回指定类型的孩子
		 * @param node		被寻找的父节点
		 * @param tClass	子类孩子的过滤, 如果为 null, 则返回所有孩子
		 * @return			返回孩子列表, 失败为 null
		 */
		static public function findChildren(node:DisplayObjectContainer, tClass:Class=null):Array{
			var arr:Array = new Array;
			if(tClass == null) tClass = DisplayObject;
			for(var i:int=0; i<node.numChildren; i++){
				var disp:DisplayObject = node.getChildAt(i);
				if(disp is tClass) arr.push(disp);
			}
			return (arr.length>0)? arr: null;
		}
		
		/**
		 * 把 target 移动到前面, 使其在父容器中的位置, 为最后一个孩子
		 */
		static public function moveFront(target:DisplayObject):void{
			if(!target || !target.parent) return;
			target.parent.setChildIndex(target, target.parent.numChildren-1);
		}
		
		// 禁止某个控件的鼠标消息
		static public function disableMouseEvent(parent:DisplayObjectContainer, ...nameList):void{
			for each(var name:String in nameList){
				var disp:DisplayObject = parent.getChildByName(name);
				if(disp is InteractiveObject) (disp as InteractiveObject).mouseEnabled = false;
				if(disp is DisplayObjectContainer) (disp as DisplayObjectContainer).mouseChildren = false;
			}
		}
		
		/**
		 * 根据disp和vars参数画多条水平线
		 * @param disp		要画线的sprite
		 * @param rect		画线的长宽位置
		 * @param odds		按此比例段画线
		 * @param color		线的颜色
		 * @param alpha		线的alpha值
		 */		
		public static function drawHorizLines(disp:Sprite,rect:Rectangle,odds:Array,color:uint=0x000000,thickness:Number=1,alpha:Number=1):void
		{
			disp.graphics.lineStyle(thickness,color,alpha);
			for(var i:int=1;i<(odds.length-1);i++){
				var arg:int = rect.height*odds[i];
				disp.graphics.moveTo((rect.x),(rect.y+i*arg));
				disp.graphics.lineTo((rect.x+rect.width),(rect.y+i*arg))
			}
		}
		
		/**
		 * 根据disp和vars参数画多条竖线
		 * @param disp		要画线的sprite
		 * @param rect		画线的长宽位置
		 * @param odds		按此比例段画线
		 * @param color		线的颜色
		 * @param alpha		线的alpha值
		 */		
		public static function drawVertLines(disp:Sprite,rect:Rectangle,odds:Array,color:uint=0x000000,thickness:Number=1,alpha:Number=1):void
		{
			disp.graphics.lineStyle(thickness,color,alpha);
			for(var i:int=1;i<(odds.length-1);i++){
				var arg:int = rect.width*odds[i];
				disp.graphics.moveTo((rect.x+i*arg),(rect.y));
				disp.graphics.lineTo((rect.x+i*arg),(rect.y+rect.height))
			}
		}
		
		//设置文本标签
		public static function setTextTag(txt:String,tag:String):String
		{
			return "<" + tag + ">" + txt + "</" + tag + ">";
		}
		//设置文本标签
		public static function setTextClass(txt:String,cla:String):String
		{
			return "<span class='" + cla + "'>" + txt + "</span>";
		}
		
		/**
		 * 将容器内的显示单位排列
		 * @param disp
		 * @param spacing		间距
		 * @param hvArrange		排列方式，0为横排，1为竖排
		 */		
		public static function arrangeDisp(disp:DisplayObjectContainer,spacing:int=0,hvArrange:int=1):void
		{
			var xyArg:String = hvArrange?"y":"x";
			var whArg:String = hvArrange?"height":"width";
			var tmpXY:int = 0;
			for(var i:int;i<disp.numChildren;i++){
				var dp:DisplayObject = disp.getChildAt(i);
				dp[xyArg] = tmpXY;
				tmpXY = tmpXY + dp[whArg] + spacing;
			}
		}
		
		/**
		 * 按行列二维排列容器里的项,先从左到右，再从上到下排
		 * @param disp
		 * @param perColNum		每列有x项,如果为0则一排,横排
		 * @param colWidth		每列的列宽,如果为0则按item的宽度自动排列,即列宽==项宽
		 * @param rowHeight		每列的列高度,如果为0则按item的高度自动向下排列,即行高==项高
		 */
		public static function arrangeDispRC(disp:DisplayObjectContainer,perColNum:int=1,colWidth:int=0,rowHeight:int=0,spacing:int=0):void
		{
			var tmpY:int=0,tmpX:int=0;
			for(var i:int=0;i<disp.numChildren;i++){
				var dp:DisplayObject = disp.getChildAt(i);
				if(i && !(i%perColNum) && perColNum!=0){
					tmpY = tmpY + spacing + (rowHeight?rowHeight:dp.height);
					tmpX = 0;
				}
				dp.x = tmpX;
				tmpX = tmpX + (colWidth || dp.width) + spacing;
				dp.y = tmpY;
			}
		}
		
		/**
		 * 根据比率排列容器里的显示对象
		 * @param disp	要排列的对象
		 * @param width	排列后的总宽度
		 * @param odds	比率
		 */
		public static function arrangDispByOdds(disp:DisplayObjectContainer,width:int,odds:Array,isWidth:Boolean=false):void
		{
			var tmpx:int=0;
			for(var i:int=0;i<disp.numChildren;i++){
				var dp:DisplayObject = disp.getChildAt(i);
				if(isWidth) dp.width = Math.round(odds[i]*width);
				dp.x = tmpx;
				tmpx += Math.round(odds[i]*width);
			}
		}
		
		/**
		 * 获取通用阴影滤镜
		 * DropShadowFilter factory method, used in many of the components.
		 * @param dist The distance of the shadow.
		 * @param knockout Whether or not to create a knocked out shadow.
		 */
		public static function getShadow(dist:Number, blur:Number=5, color:uint=0x000000):DropShadowFilter
		{
			return new DropShadowFilter(dist, 45, color, 1, blur, blur, .3, 1);
		}
		
		// 设置下一帧回调函数
		static private var _sprit:Sprite;
		static public function setNextFrameCallback(fn:Function, ...args):void{
			if(!_sprit) _sprit = new Sprite;
			_sprit.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			function onEnterFrame(event:Event):void{
				_sprit.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
				fn.apply(null, args);
			}
		}
		
		/**
		 * 批量给容器里属性斌arr数组里的值
		 * @param arr		数组数据
		 * @param disp		要斌值的容器
		 * @param prefix	容器里面属性名前缀
		 */
		static public function batParseArrTodisp(arr:Array,disp:DisplayObjectContainer,prefix:String="txt_arr",isHtml:Boolean=false):void
		{
			var txt:TextField;
			for(var i:int=0;i<arr.length;i++){
				if(!disp.getChildByName(prefix+i)) continue;
				if(disp.getChildByName(prefix+i) is TextField){
					txt = (disp.getChildByName(prefix+i) as TextField);
					if(!isHtml) txt.text = String(arr[i]);
					else txt.htmlText = String(arr[i]);
				}else if(disp[prefix+i] is MovieClip){
					(disp[prefix+i] as MovieClip).gotoAndStop(int(arr[i]));
				}
			}
		}
		
		/**
		 * 批量给容器里属性斌data里对应同名的值
		 * @param data		数据对象
		 * @param disp		要斌值的容器
		 */
		static public function batParseObjTodisp(data:Object,disp:DisplayObject,isHtml:Boolean=false):void
		{
			var txt:TextField;
			var desc:XMLList = describeType( disp )["variable"];
			// 设置 obj 的每个属性 prop
			for each(var prop:XML in desc)
			{
				var propName:String = prop.@name;			// 变量名
				var propType:String = prop.@type;			// 变量类型
				if(!data.hasOwnProperty(propName)) continue;
				if(disp[propName] is TextField){
					txt = (disp[propName] as TextField);
					if(!isHtml) txt.text = String(data[propName]);
					else txt.htmlText = String(data[propName]);
				}else if(disp[propName] is MovieClip){
					(disp[propName] as MovieClip).gotoAndStop(int(data[propName]));
				}
			}
		}
		
		// 比率参数为假或者不存在则按数组里字符的长度平均分配
		/**
		 * 根据数组数据的字符长度比分配比率
		 * @param datas	数组数据
		 * @return 
		 */
		public static function oddsByDatas(datas:Object):Array
		{
			var sum:int = 0,i:int=0,odds:Array = [];
			// 先算出字符长度
			for each(var s:String in datas){
				sum += (s.length==0)?1:s.length;
			}
			// 再算出数组数据中每个数据长度的比例
			for each(s in datas){
				odds.push(((s.length==0)?1:s.length)/sum);
			}
			return odds;
		}
		
		/**
		 * 删除字符串里第一个匹配的字符串refStr
		 * 如str = "123455"; str = delstr(str,"345");
		 * 输出str为 125;
		 * @param srcStr
		 * @param refStr
		 */		
		public static function delStr(srcStr:String,refStr:String):String
		{
			var s1:String = srcStr.substring(0,srcStr.indexOf(refStr));
			var s2:String = srcStr.substring((s1.length+refStr.length),srcStr.length);
			return s1+s2;
		}
		
		/**
		 * 画箭头
		 * @param sp	给图形画箭头
		 */		
		public static function drawArrow(dr:int=0,dis:int=11):Shape
		{
			var shap:Shape = new Shape();
			shap.graphics.beginFill(0x666666);
			if(dr==0){	//指向下
				shap.graphics.moveTo(0,0);
				shap.graphics.lineTo(dis,0);
				shap.graphics.lineTo(dis/2,dis);
			}
			else if(dr==1){	//指向上
				shap.graphics.moveTo(dis/2,0);
				shap.graphics.lineTo(0,dis);
				shap.graphics.lineTo(dis,dis);
			}
			else if(dr==2){	//指向左
				shap.graphics.moveTo(dis,0);
				shap.graphics.lineTo(dis,dis);
				shap.graphics.lineTo(0,dis/2);
			}
			else if(dr==3){	//指向右
				shap.graphics.moveTo(0,0);
				shap.graphics.lineTo(0,dis);
				shap.graphics.lineTo(dis,dis/2);
			}
			shap.graphics.endFill();
			return shap;
		}
		
		/**
		 * 替换 newObj 成为 existObj, 并按它的位置对齐, 然后把 existObj 变为 newObj 的孩子, 并使名字相同
		 */
		static public function replace(newObj:DisplayObjectContainer, existObj:DisplayObject):void{
			
			existObj.parent.addChild(newObj);
			existObj.parent.swapChildren(newObj, existObj);
			
			var x:int = existObj.x;
			var y:int = existObj.y;
			var w:int = existObj.width;
			var h:int = existObj.height;
			
			newObj.addChild(existObj);
			existObj.x = 0;
			existObj.y = 0;
			
			newObj.x = x;
			newObj.y = y;
			newObj.width = w;
			newObj.height = h;
			newObj.name = existObj.name;
		}
	}
}